#include <common.h>
#include <paging.h>
#include <elf.h>

extern page_directory_t *current_directory;

int openModule_elf(char* name, int offset)
{
     elf_header_t* header;
     
     /* Put header information into header struct */
        header = (elf_header_t*) offset;
     
     /* Check for any errors */
     if(header->ident[0] != 0x7f || header->ident[1] != 'E' || header->ident[2] != 'L' || header->ident[3] != 'F')
     {
          printf("Error opening %s! %s is not ELF\n",name,name);
          return 1;
     }
     
     if(header->ident[4] != 1)
     {
          printf("Error opening %s! ELF not designed for x86-32 architecture!\n",name);
          return 1;
     }
     
     if(header->ident[5] != 1)
     {
          printf("Error opening %s! ELF uses wrong encoding type. LSB ONLY supported!\n",name);
          return 1;
     }
     
     if(header->flags)
     {
          printf("Error opening %s! ELF must not contain flags in header!\n",name);
          return 1;
     }
     
     if(relocModule_elf(header,offset) != 1)
     {
          printf("Error opening %s! Cannot relocate ELF image!\n",name);
          return 1;
     }
     
     /* Call the program */
     printf("calling executable\n");
     __asm__ __volatile("call %0" : : "a" (header->entry));
     
     return 0;
}

int relocModule_elf(elf_header_t* header, int offset)
{
    int i;
        elf_program_header_t* pHeader;
        page_t* page;
    
    for(i = 0; i < header->phnum; i++)
    {
                pHeader = (elf_program_header_t*) ((unsigned long) header + header->phoff + i * header->phentsize);
          
          /* Check if its loadable */
          if( pHeader->type == PT_LOAD ) /* PT_LOAD == 1 */
          {
              if(pHeader->vaddr < 0x1000)
              {
                   printf("Virtual address (0x%x) below 1MB\n",pHeader->vaddr,i);
                   return 0;
              }
              
              printf("Allocate some space at vaddr (0x%x)\n",pHeader->vaddr);
                          page = get_page(pHeader->vaddr, 1, current_directory);
                          alloc_frame(page, 0, 1);
              printf("Page's location: 0x%x\n",page->frame);
              printf("memcpy() the program data there\n");
              printf("0x%x - 0x%x - 0x%x\n",pHeader->vaddr,offset+pHeader->offset,pHeader->fileSize);
              printf("header:0x%x pHeader->offset:0x%x\n",offset,pHeader->offset);
              
                          memcpy(pHeader->vaddr, offset+pHeader->offset, pHeader->fileSize);
              
              if(pHeader->fileSize < pHeader->memSize)
                   printf("Filesize was less than memory size\n");
                   /* memset() the remaining memory with zeroes */
                          memset(pHeader->vaddr+pHeader->fileSize, 0, pHeader->memSize-pHeader->fileSize);
              
          }
    }
    return 1;
}